Skip to content

Conversation

@hyperfinitism
Copy link
Contributor

@hyperfinitism hyperfinitism commented Dec 29, 2025

Background

This pull request aims to implement the attestation flow described in Issue #116.

Currently, on Azure Confidential VMs, snpguest (with the hyperv feature) only retrieves the boot-time SNP report that the paravisor writes into vTPM NV index 0x01400001.

To request a fresh SNP report bound to arbitrary 64-byte data, the following attestation flow is required:

  1. The guest writes 64 bytes of data (referred to as user-data) to NV index 0x01400002
  2. The paraviser detects the NV write, constructs a JSON object called Runtime Claims containing the user-data, the vTPM attestation public key, VM configuration, etc., and passes the hash value of this JSON as REPORT_DATA to the ASP
  3. The ASP issues the SNP Report
  4. The paraviser writes the SNP Report, Runtime Claims, and other metadata (e.g. the hash algorithm) to NV index 0x01400001
  5. The guest reads these from 0x01400001 to obtain the SNP Report

This PR implements this flow.

What's changed

Flag name (breaking change)

  • snpguest report: -p, --platform-a, --azure-cvm

CLI behavior (breaking change)

Command Previous behavior New behavior
snpguest report report.bin report-data.bin -a Read existing SNP report from NV 0x01400001 → write both files Write supplied report-data.bin to NV 0x01400002 → trigger ASP → read fresh SNP report from NV 0x01400001 (no overwrite to report-data.bin)
snpguest report report.bin report-data.bin -a -r -a (formerly -p) conflicts with -r Generate random 64-byte nonce into report-data.bin → trigger fresh report as above

With these semantics, the REPORT_DATA field in the report will no longer match the raw report-data.bin, since the paravisor computes user-dataRuntime Claims → SHA hash digest → REPORT_DATA.

Code Structure

  • the hyperv module splits into separate submodules for clarity

Resolved issues & related PRs

Item Status
Issue #134 Resolved by this PR
PR #136 Can be closed as obsolete if this PR is accepted
Issue #116 Remains open because handling of Runtime Claims JSON is not implemented yet

Test

Test procedure

# Build
git clone https://github.com/hyperfinitism/snpguest -b feature/fresh-azcvm-report
cd snpguest
cargo build -r --features hyperv

# Request SNP report via vTPM using random nonce
sudo ./target/release/snpguest report report.bin report-data.bin -r -a -v 0

# Display SNP report
./target/release/snpguest display report report.bin

# Fetch VCEK cert chain
./target/release/snpguest fetch ca pem . -r report.bin
./target/release/snpguest fetch vcek pem . report.bin

# Verify VCEK cert chain and report signature
./target/release/snpguest verify certs .
./target/release/snpguest verify attestation . report.bin

Test Environment

  • VM: Microsoft Azure Standard DC2as v5
  • Processor: AMD 3rd Gen EPYC
  • OS Image: Ubuntu Pro 24.04 LTS (Confidential VM) - x64 Gen 2
    • Kernel: 6.14.0-1014-azure-fde
  • Security
    • Security type: Confidential
    • Enable secure boot: Enabled
    • Enable vTPM: Enabled
    • Integrity monitoring: Enabled

@DGonzalezVillal
Copy link
Member

Hello @hyperfinitism,

Currently reviewing and testing on my side. Just had a quick question for you. With these changes would the -a (previously -p) flag still be needed?

What I mean by this is that if someone builds with the hyperv feature enabled, then could we make it so that they only request reports from the TPM? or if hyperv is enabled they could still get reports from either the asp and the tpm?

@hyperfinitism
Copy link
Contributor Author

About the flag name

The former --platform flag was originally named to indicate that the report was obtained using platform-prepared REPORT_DATA, in contrast to --random, which uses a randomly generated nonce.

However, as already mentioned, this name is misleading. In reality, at VM boot time, the paravisor running at VMPL0 requests an attestation report from the ASP and writes it into the vTPM NV index. The command snpguest report --platform merely reads this pre-existing report; it does not request a new report using REPORT_DATA prepared by the platform at invocation time.

In this PR, the behaviour is fundamentally different. The guest OS provides 'user data' to the paravisor (via the vTPM NV index), the paravisor derives REPORT_DATA from it, and then requests a fresh attestation report from the ASP using that REPORT_DATA. Since the semantic meaning of the flag changes completely, I believe it is better to rename it rather than keep the old name.

As an alternative, for backward compatibility, we could keep the existing --platform flag for the functionality "retrieve the report and REPORT_DATA currently stored in the vTPM", and introduce a new flag --azure-cvm specifically for requesting a fresh report via the paravisor.

Behaviour when built with the hyperv feature

Even when built with the hyperv feature, the user can still attempt to request a report via /dev/sev-guest by not specifying the --azure-cvm flag.

However, at the moment, Azure CVM hides /dev/sev-guest from the guest OS. As a result, such a command will always fail on Azure CVM.

@DGonzalezVillal
Copy link
Member

Yeah I understand the differences. What I'm asking is that if it would make sense to only request reports from the NV index if the tool was built with the hyperv feature, essentially removing the --azure-cvm flag. Or is there a reason that we would want to keep the functionality to get it from /dev/sev-guest in a hyperv snpguest. I guess for people that would want to share the same snpuguest binary between azure guests and regular linux ones, but I'm open to hear your thoughts.

I don't really mind keeping the backward compatibility for --platform since this addition will be a breaking change regardless.

@hyperfinitism
Copy link
Contributor Author

Remove the --platform (--azure-cvm) flag, and fully determine behavior of the report command solely by the build feature, meaning:

  • Build with hyperv → Always request reports via /dev/tpm*
  • Build without hyperv → Always request reports via /dev/sev-guest

Is my understanding correct? I agree this approach represents a very natural and clean design. It simplifies both the CLI interface and the internal logic.

On the other hand, as you pointed out, the current approach of a single binary with hyperv support handling both environments at runtime offers equivalent benefits. In practice, users may want to reuse the same binary across:

  • regular SEV-SNP CVMs,
  • Azure CVMs powered by OpenHCL, and potentially
  • future environments (e.g. CVMs with SVSM-vTPM).

@elmarco
Copy link

elmarco commented Jan 21, 2026

@hyperfinitism where is the documentation for the NV index 0x01400002 ?
How did you configure your Azure VM to make it work?

thanks

@hyperfinitism
Copy link
Contributor Author

@elmarco
The details for Azure CVM attestation can be found in Confidential VM Guest Attestation Design Detail. This documentation was first published in Jul 2024, after the --platform flag was introduced in #16 (Aug 2023).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants